package com.xiaoshu.util;

import com.aspose.cells.Workbook;
import com.aspose.pdf.*;
import com.aspose.words.Node;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.PdfPage;
import com.itextpdf.text.pdf.PdfWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.LinkedList;
import java.util.List;

/**
 * @author 何小树
 * @className PdfConvertUtil
 * @description pdf文件转换工具类
 */
public class PdfConvertUtil {

    private static final Logger log = LoggerFactory.getLogger(PdfConvertUtil.class);

    /**
     * pdf去除水印
     * 注意转换前，观察打印预览是否满足直接打印
     * @param sourceFile 源文件流
     * @param outPutFile 输出文件
     * @return 转换文件
     */
    public static File removeWatermark(InputStream sourceFile, File outPutFile,String waterMark) {
        try {
            long start = System.currentTimeMillis();
            logFileInfo(sourceFile);
            boolean creatFlag = true;
            if (!outPutFile.exists()) {
                creatFlag = outPutFile.createNewFile();
            }
            if (creatFlag) {
                // 加载PDF文件
                Document document = new Document(sourceFile);
                // 遍历每一页
                for (int i = 1; i <= document.getPages().size(); i++) {
                    Page page = document.getPages().get_Item(i);

                    // 获取该页中的所有文本
                    TextFragmentAbsorber textFragmentAbsorber = new TextFragmentAbsorber();
                    page.accept(textFragmentAbsorber);
                    // 查找是否存在水印
                    for (TextFragment textFragment : textFragmentAbsorber.getTextFragments()) {
                        String text = textFragment.getText();
                        if (textFragment.getText().equals(waterMark)) {
                            // 删除水印
                            textFragment.setText("");
                        }
                    }
                }
                logTime(start);
                document.save(outPutFile.getAbsolutePath());
                return outPutFile;
            } else {
                log.info("输出文件创建失败");
                return null;
            }
        } catch (Exception e) {
            outPutFile.deleteOnExit();
            log.error("FileConvertUtil-removeWatermark() 文件转换异常", e);
            return null;
        }
    }

    /**
     * ppt转pdf
     * 注意转换前，观察打印预览是否满足直接打印
     *
     * @param images     图片集合
     * @param outPutFile 输出文件
     * @return 转换文件
     */
    public static File imgToPdf(List<File> images, File outPutFile) {
        try {
            long start = System.currentTimeMillis();
            com.itextpdf.text.Document doc = new com.itextpdf.text.Document();
            boolean creatFlag = true;
            if (!outPutFile.exists()) {
                creatFlag = outPutFile.createNewFile();
            }
            if (creatFlag) {
                PdfWriter.getInstance(doc, Files.newOutputStream(outPutFile.toPath()));
                doc.open();
                for (File image : images) {
                    doc.newPage();
                    Image png1 = Image.getInstance(image.getAbsolutePath());
                    float heigth = png1.getHeight();
                    float width = png1.getWidth();
                    int percent = getImgPercent(heigth, width);
                    png1.setAlignment(Image.MIDDLE);
                    png1.scalePercent(percent + 3);
                    doc.add(png1);
                }
                doc.close();
                logTime(start);
                return outPutFile;
            } else {
                log.info("输出文件创建失败");
                return null;
            }
        } catch (Exception e) {
            outPutFile.deleteOnExit();
            log.error("FileConvertUtil-imgToPdf() 文件转换异常", e);
            return null;
        }
    }

    /**
     * 读取word文件内容
     * 注意转换前，观察打印预览是否满足直接打印
     *
     * @param sourceFile 源文件流
     * @return String
     */
    public static List<String> readDoc(InputStream sourceFile) {
        try {
            List<String> res = new LinkedList<>();
            long start = System.currentTimeMillis();
            logFileInfo(sourceFile);
            com.aspose.words.Document document = new com.aspose.words.Document(sourceFile);
            // 遍历文档中的所有节点
            for (Node node : document) {
                res.add(node.getText());
            }
            logTime(start);
            return res;
        } catch (Exception e) {
            log.error("FileConvertUtil-readDoc() 文件读取异常", e);
            return null;
        }
    }

    /**
     * 读取pdf内容
     * 注意转换前，观察打印预览是否满足直接打印
     *
     * @param sourceFile 源文件流
     * @return String
     */
    public static String readPdf(InputStream sourceFile) {
        try {
            long start = System.currentTimeMillis();
            logFileInfo(sourceFile);
            Document document = new Document(sourceFile);
            TextAbsorber textAbsorber = new TextAbsorber();
            document.getPages().accept(textAbsorber);
            logTime(start);
            return textAbsorber.getText();
        } catch (Exception e) {
            log.error("FileConvertUtil-readPdf() 文件读取异常", e);
            return null;
        }
    }


    /**
     * pdf转pdf
     * 注意转换前，观察打印预览是否满足直接打印
     *
     * @param sourceFile 源文件流
     * @param outPutFile 输出文件
     * @return 转换文件
     */
    public static File pdfToTxt(InputStream sourceFile, File outPutFile) {
        try {
            long start = System.currentTimeMillis();
            logFileInfo(sourceFile);
            boolean creatFlag = true;
            if (!outPutFile.exists()) {
                creatFlag = outPutFile.createNewFile();
            }
            if (creatFlag) {
                // 加载PDF文件
                Document document = new Document(sourceFile);
                // 创建文本提取器
                TextAbsorber textAbsorber = new TextAbsorber();
                // 提取文本
                document.getPages().accept(textAbsorber);
                // 将提取的文本保存到txt文件
                String text = textAbsorber.getText();
                writeFileContent(text, Files.newOutputStream(outPutFile.toPath()), 1024);
                logTime(start);
                return outPutFile;
            } else {
                log.info("输出文件创建失败");
                return null;
            }
        } catch (Exception e) {
            outPutFile.deleteOnExit();
            log.error("FileConvertUtil-pdfToTxt() 文件转换异常", e);
            return null;
        }
    }

    /**
     * text转pdf
     * 注意转换前，观察打印预览是否满足直接打印
     *
     * @param sourceFile 源文件流
     * @param outPutFile 输出文件
     * @return 转换文件
     */
    public static File txtToPdf(InputStream sourceFile, File outPutFile) {
        return wordToPdf(sourceFile, outPutFile);
    }


    /**
     * ppt转pdf
     * 注意转换前，观察打印预览是否满足直接打印
     *
     * @param sourceFile 源文件流
     * @param outPutFile 输出文件
     * @return 转换文件
     */
    public static File pdfToPpt(InputStream sourceFile, File outPutFile) {
        try {
            long start = System.currentTimeMillis();
            logFileInfo(sourceFile);
            boolean creatFlag = true;
            if (!outPutFile.exists()) {
                creatFlag = outPutFile.createNewFile();
            }
            if (creatFlag) {
                Document document = new Document(sourceFile);
                document.save(outPutFile.getAbsolutePath(), com.aspose.pdf.SaveFormat.Pptx);
                logTime(start);
                return outPutFile;
            } else {
                log.info("输出文件创建失败");
                return null;
            }
        } catch (Exception e) {
            outPutFile.deleteOnExit();
            log.error("FileConvertUtil-pdfToPpt() 文件转换异常", e);
            return null;
        }
    }

    /**
     * ppt转pdf
     * 注意转换前，观察打印预览是否满足直接打印
     *
     * @param sourceFile 源文件流
     * @param outPutFile 输出文件
     * @return 转换文件
     */
    public static File pptToPdf(InputStream sourceFile, File outPutFile) {
        try {
            long start = System.currentTimeMillis();
            logFileInfo(sourceFile);
            boolean creatFlag = true;
            if (!outPutFile.exists()) {
                creatFlag = outPutFile.createNewFile();
            }
            if (creatFlag) {
                Document document = new Document(sourceFile);
                document.save(outPutFile.getAbsolutePath(), com.aspose.pdf.SaveFormat.Pptx);
                logTime(start);
                return outPutFile;
            } else {
                log.info("输出文件创建失败");
                return null;
            }
        } catch (Exception e) {
            outPutFile.deleteOnExit();
            log.error("FileConvertUtil-pptToPdf() 文件转换异常", e);
            return null;
        }
    }


    /**
     * pdf 转 excel
     * 注意转换前，观察打印预览是否满足直接打印
     *
     * @param sourceFile 源文件流
     * @param outPutFile 输出文件
     * @return 转换文件
     */
    public static File pdfToExcel(InputStream sourceFile, File outPutFile) {
        try {
            long start = System.currentTimeMillis();
            logFileInfo(sourceFile);
            boolean creatFlag = true;
            if (!outPutFile.exists()) {
                creatFlag = outPutFile.createNewFile();
            }
            if (creatFlag) {
                Document document = new Document(sourceFile);
                document.save(outPutFile.getAbsolutePath(), com.aspose.pdf.SaveFormat.Excel);
                logTime(start);
                return outPutFile;
            } else {
                log.info("输出文件创建失败");
                return null;
            }
        } catch (Exception e) {
            outPutFile.deleteOnExit();
            log.error("FileConvertUtil-pdfToExcel() 文件转换异常", e);
            return null;
        }
    }

    /**
     * excel转pdf
     * 注意转换前，观察打印预览是否满足直接打印
     *
     * @param sourceFile 源文件流
     * @param outPutFile 输出文件
     * @return 转换文件
     */
    public static File excelToPdf(InputStream sourceFile, File outPutFile) {
        try {
            long start = System.currentTimeMillis();
            logFileInfo(sourceFile);
            boolean creatFlag = true;
            if (!outPutFile.exists()) {
                creatFlag = outPutFile.createNewFile();
            }
            if (creatFlag) {
                Workbook workbook = new Workbook(sourceFile);
                workbook.save(outPutFile.getAbsolutePath(), com.aspose.cells.SaveFormat.PDF);
                logTime(start);
                return outPutFile;
            } else {
                log.info("输出文件创建失败");
                return null;
            }
        } catch (Exception e) {
            outPutFile.deleteOnExit();
            log.error("FileConvertUtil-excelToPdf() 文件转换异常", e);
            return null;
        }
    }

    /**
     * pdf转word
     *
     * @param sourceFile 源文件流
     * @param outPutFile 输出文件
     * @return 转换文件
     */
    public static File wordToPdf(InputStream sourceFile, File outPutFile) {
        try {
            long start = System.currentTimeMillis();
            logFileInfo(sourceFile);
            boolean creatFlag = true;
            if (!outPutFile.exists()) {
                creatFlag = outPutFile.createNewFile();
            }
            if (creatFlag) {
                com.aspose.words.Document document = new com.aspose.words.Document(sourceFile);
                document.save(outPutFile.getAbsolutePath(), com.aspose.words.SaveFormat.PDF);
                logTime(start);
                return outPutFile;
            } else {
                log.info("输出文件创建失败");
                return null;
            }
        } catch (Exception e) {
            outPutFile.deleteOnExit();
            log.error("FileConvertUtil-wordToPdf() 文件转换异常", e);
            return null;
        }
    }

    /**
     * pdf转word
     *
     * @param sourceFile 源文件流
     * @param outPutFile 输出文件
     * @return 转换文件
     */
    public static File pdfToWord(InputStream sourceFile, File outPutFile) {
        try {
            long start = System.currentTimeMillis();
            logFileInfo(sourceFile);
            boolean creatFlag = true;
            if (!outPutFile.exists()) {
                creatFlag = outPutFile.createNewFile();
            }
            if (creatFlag) {
                Document document = new Document(sourceFile);
                document.save(outPutFile.getAbsolutePath(), com.aspose.pdf.SaveFormat.DocX);
                logTime(start);
                return outPutFile;
            } else {
                log.info("输出文件创建失败");
                return null;
            }
        } catch (Exception e) {
            outPutFile.deleteOnExit();
            log.error("FileConvertUtil-pdfToWord() 文件转换异常", e);
            return null;
        }
    }

    private static String getPrefix(File file) {
        String fileName = file.getName();
        return fileName.substring(fileName.lastIndexOf(".") + 1);
    }

    private static void logFileInfo(InputStream sourceFile) throws IOException {
        int available = sourceFile.available();
        if (available == 0) {
            log.info("文件不存在");
            return;
        }
        String fileSizeStr = convertBytesToSize(available);
        log.info("开始转换文件：源文件大小: " + fileSizeStr);
    }

    private static void logTime(long start) {
        long end = System.currentTimeMillis();
        long useTime = end - start;
        if (useTime > 1000) {
            log.info("耗时：" + (useTime / 1000) + "s");
        } else {
            log.info("耗时：" + (useTime) + "ms");
        }
    }

    public static int getImgPercent(float h, float w) {
        int p = 0;
        float p2 = 0.0f;
        p2 = 530 / w * 100;
        p = Math.round(p2);
        return p;
    }

    /**
     * 按行写入文本内容
     *
     * @param content 文本内容集合
     * @param os      输出流
     * @param m       缓存 / M
     */
    public static void writeFileContent(String content, OutputStream os, int m) {
        BufferedWriter bw;
        try {
            BufferedOutputStream bos = new BufferedOutputStream(os);
            bw = new BufferedWriter(new OutputStreamWriter(bos, StandardCharsets.UTF_8), m == 0 ? 5 * 1024 * 1024 : m * 1024 * 1024);
            bw.write(content);
            bw.flush();
            bw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static String convertBytesToSize(long bytes) {
        String size = "";
        if (bytes >= 1024 * 1024 * 1024) {
            size = String.format("%.2f GB", (double) bytes / (1024 * 1024 * 1024));
        } else if (bytes >= 1024 * 1024) {
            size = String.format("%.2f MB", (double) bytes / (1024 * 1024));
        } else if (bytes >= 1024) {
            size = String.format("%.2f KB", (double) bytes / 1024);
        } else {
            size = String.format("%d Bytes", bytes);
        }
        return size;
    }

}
